package com.example.wl.tiaoyinqi;

import android.Manifest;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.wl.tiaoyinqi.audio.AudioProcess;
import com.example.wl.tiaoyinqi.yueqifragments.GuitarFragment;
import com.example.wl.tiaoyinqi.yueqifragments.GuqinFragment;
import com.example.wl.tiaoyinqi.yueqifragments.GuzhengFragment;
import com.example.wl.tiaoyinqi.yueqifragments.Lyre15Fragment;
import com.example.wl.tiaoyinqi.yueqifragments.Lyre7Fragment;
import com.example.wl.tiaoyinqi.yueqifragments.PipaFragment;
import com.example.wl.tiaoyinqi.yueqifragments.ShouboqinFragment;
import com.example.wl.tiaoyinqi.yueqifragments.YoukeliliFragment;


/**
 * Created by wl on 2016/5/23.
 */

public class MainActivity extends FragmentActivity implements
        MyCallbacks,
        View.OnClickListener {
    private float fre = 329.62756f;
    private double jzFre = 440.0;
    private float prePos;
    private int xuanzhuandianY;
    private boolean isExact;

    private float[] k = new float[]{-1, -1};
    private int i = 0;
    private float j = -1;

    private AudioProcess audioProcess;
    private RotateAnimation animation;
    private ShuomingDialog mShuomingDialog;
    private SelectDialog mSelectDialog;
    private TipDialog mTipDialog;
    private FragmentManager fm;
    private TextView mTextView, mLetText, mNumText, mXianNum;
    private ImageView pointer;
    private Fragment guitarFragment, pipaFragment, guzhengFragment, shouboqinFragment,
            guqinFragment, lyre7Fragment, lyre15Fragment, youkeliliFragment;
    private String lastShowFragmentTag;
    private int currentFragmentTagNum;
    private SoundPool mSoundPool;
    private int mSoundId;

    private int[] lastShowXian = new int[]{
            0, 0, 0, 0, 0, 0, 0, 0
    };

    private static final double RATE_40 = 1.02337391;       //40音分相差倍数（每半音相差100音分）
    private static final double RATE_20 = 1.01161945;       //20音分相差倍数（每半音相差100音分）
    private static final double RATE_10 = 1.00579941;       //10音分相差倍数
    private static final double RATE = 1.05946309436;       //每半音相差倍数
    private static final double RATE_2 = 1.12246204831;     //每两个半音相差倍数

    public static final int TAG_NUM_guitar = 0;
    public static final int TAG_NUM_shouboqin = 1;
    public static final int TAG_NUM_lyre7 = 2;
    public static final int TAG_NUM_lyre15 = 3;
    public static final int TAG_NUM_guzheng = 4;
    public static final int TAG_NUM_guqin = 5;
    public static final int TAG_NUM_pipa = 6;
    public static final int TAG_NUM_youkelili = 7;

    private final String LAST_SHOW_FRAGMENT = "last";
    private final String TAG_shuomingDialog = "shuoming";
    private final String TAG_selectDialog = "select";
    private final String TAG_tipDialog = "tip";
    private final String[] TAGs = new String[]{
            "guitar", "shouboqin", "lyre7", "lyre15",
            "guzheng", "guqin", "pipa", "youkelili"
    };

    //音符
    private final String[] STR_LET = new String[]{
            "C", "♯C", "D", "♯D", "E", "F", "♯F", "G", "♯G", "A", "♯A", "B"
    };

    //各乐器各参照弦音符
    private final int[][] num_first_letter = new int[][]{
            {9, 4}, {7, 4, 0}, {7, 2}, {0, 4, 7}, {4, 4, 4, 4, 2}, {5, 0}, {9}, {0}
    };

    //各参照弦音符下标数字
    private final int[][] first_num = new int[][]{
            {2, 2}, {4, 5, 6}, {4, 4}, {5, 4, 3}, {5, 4, 3, 2, 2}, {2, 2}, {3}, {4}
    };

    //各参照弦所参照的mid音频文件id
    private final int[][] midPath = new int[][]{
            {R.raw.a2_110, R.raw.e2_82},
            {R.raw.f4_349, R.raw.d5sheng_622, R.raw.g5sheng_831},
            {R.raw.f4_349, R.raw.c4_262},
            {R.raw.a4sheng_466, R.raw.c4_262, R.raw.g3_196},
            {R.raw.d5sheng_622, R.raw.c4_262, R.raw.d3_147, R.raw.e2_82, R.raw.b1_62},
            {R.raw.e2_82, R.raw.b1_62},
            {R.raw.g3_196},
            {R.raw.c4_262}
    };

    //各乐器各参照弦弦与mid音频相差半音数
    private final int[][] num_first = new int[][]{
            {0, 0}, {2, 1, 4}, {2, 2}, {2, 4, 0}, {1, 4, 2, 0, 3}, {1, 1}, {2}, {0}
    };

    //各乐器各弦相对参照弦相差半音数,为0的即为参照弦
    private final int[][] num_xians = new int[][]{
            {19, 14, 10, 5, 0, 0},
            {0, 2, 4, 5, 7, 0, 1, 3, 5, 7, 0, 2, 4, 5, 7},
            {9, 7, 4, 2, 0, 2, 0},
            {7, 5, 4, 2, 0, 7, 5, 3, 1, 0, 7, 5, 4, 2, 0},
            {10, 7, 5, 2, 0, 10, 7, 5, 2, 0, 10, 7, 5, 2, 0, 10, 7, 5, 2, 0, 0},
            {9, 7, 4, 2, 0, 2, 0},
            {12, 7, 5, 0},
            {9, 4, 0, 7}
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mSoundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
        mSoundId = -1;

        fm = getSupportFragmentManager();

        if (savedInstanceState != null) {
            guitarFragment = fm.findFragmentByTag(TAGs[TAG_NUM_guitar]);
            pipaFragment = fm.findFragmentByTag(TAGs[TAG_NUM_pipa]);
            guzhengFragment = fm.findFragmentByTag(TAGs[TAG_NUM_guzheng]);
            shouboqinFragment = fm.findFragmentByTag(TAGs[TAG_NUM_shouboqin]);
            guqinFragment = fm.findFragmentByTag(TAGs[TAG_NUM_guqin]);
            lyre7Fragment = fm.findFragmentByTag(TAGs[TAG_NUM_lyre7]);
            lyre15Fragment = fm.findFragmentByTag(TAGs[TAG_NUM_lyre15]);
            youkeliliFragment = fm.findFragmentByTag(TAGs[TAG_NUM_youkelili]);

            lastShowFragmentTag = savedInstanceState.getString(LAST_SHOW_FRAGMENT);

            fm.beginTransaction()
                    .hide(guitarFragment)
                    .hide(pipaFragment)
                    .hide(guzhengFragment)
                    .hide(shouboqinFragment)
                    .hide(lyre7Fragment)
                    .hide(lyre15Fragment)
                    .hide(guqinFragment)
                    .hide(youkeliliFragment)
                    .show(fm.findFragmentByTag(lastShowFragmentTag))
                    .commit();

        } else {
            guitarFragment = new GuitarFragment();
            pipaFragment = new PipaFragment();
            guzhengFragment = new GuzhengFragment();
            shouboqinFragment = new ShouboqinFragment();
            guqinFragment = new GuqinFragment();
            lyre7Fragment = new Lyre7Fragment();
            lyre15Fragment = new Lyre15Fragment();
            youkeliliFragment = new YoukeliliFragment();

            if (fm.findFragmentById(R.id.fragment_container) == null) {
                fm.beginTransaction()
                        .add(R.id.fragment_container, guitarFragment, TAGs[TAG_NUM_guitar])
                        .add(R.id.fragment_container, pipaFragment, TAGs[TAG_NUM_pipa])
                        .add(R.id.fragment_container, guzhengFragment, TAGs[TAG_NUM_guzheng])
                        .add(R.id.fragment_container, shouboqinFragment, TAGs[TAG_NUM_shouboqin])
                        .add(R.id.fragment_container, guqinFragment, TAGs[TAG_NUM_guqin])
                        .add(R.id.fragment_container, lyre7Fragment, TAGs[TAG_NUM_lyre7])
                        .add(R.id.fragment_container, lyre15Fragment, TAGs[TAG_NUM_lyre15])
                        .add(R.id.fragment_container, youkeliliFragment, TAGs[TAG_NUM_youkelili])
                        .hide(lyre15Fragment)
                        .hide(lyre7Fragment)
                        .hide(guzhengFragment)
                        .hide(pipaFragment)
                        .hide(shouboqinFragment)
                        .hide(guqinFragment)
                        .hide(youkeliliFragment)
                        .commit();
            }
            lastShowFragmentTag = TAGs[TAG_NUM_guitar];
        }

        int[] imageButtonIds = new int[]{
                R.id.activity_btn_back,
                R.id.activity_btn_help,
                R.id.activity_btn_change
        };

        for (int imageButtonId : imageButtonIds) {
            ImageButton imageButton = (ImageButton) findViewById(imageButtonId);
            imageButton.setOnClickListener(this);
        }

        mXianNum = (TextView) findViewById(R.id.xian_num);
        mTextView = (TextView) findViewById(R.id.activity_textView);
        mLetText = (TextView) findViewById(R.id.activity_textView_big);
        mNumText = (TextView) findViewById(R.id.activity_textView_small);
        pointer = (ImageView) findViewById(R.id.pointer);
        ViewGroup.MarginLayoutParams mLayoutParams =
                (ViewGroup.MarginLayoutParams) pointer.getLayoutParams();
        xuanzhuandianY = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 52,
                getResources().getDisplayMetrics()) + mLayoutParams.height / 2;

        SharedPreferences mSharedPreferences = getSharedPreferences("tiaoyinqi", MODE_PRIVATE);
        SharedPreferences.Editor editor = mSharedPreferences.edit();

        mShuomingDialog = new ShuomingDialog();
        mSelectDialog = new SelectDialog();
        mTipDialog = new TipDialog();
        if (mSharedPreferences.getInt("isFirst", 0) == 0) {
            mTipDialog.show(fm, TAG_tipDialog);
            mShuomingDialog.show(fm, TAG_shuomingDialog);
            editor.putInt("isFirst", 1).apply();
        }
        currentFragmentTagNum = TAG_NUM_guitar;
        setNoteText(0);
        try {
            startShiyin();
        } catch (IllegalStateException e) {
            Log.e("startShiyin", e.toString());
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString(LAST_SHOW_FRAGMENT, lastShowFragmentTag);
    }

    @Override
    protected void onResume() {
        super.onResume();
        try {
            if (audioProcess == null) {
                startShiyin();
            }
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        stopShiyin();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mSoundPool != null) {
            mSoundPool.release();
            mSoundPool = null;
        }
    }

    @Override
    public void onButtonOffClick(int i) {
        if (i == 0) {
            mShuomingDialog.dismiss();
        } else {
            mTipDialog.dismiss();
        }
    }

    @Override
    public void onYueqiSelect(View v) {
        switch (v.getId()) {
            case R.id.btn_guitar:
                mTextView.setText(getString(R.string.guitar));
                currentFragmentTagNum = TAG_NUM_guitar;
                showFragment(guitarFragment);
                break;
            case R.id.btn_shouboqin:
                mTextView.setText(getString(R.string.shouboqin));
                currentFragmentTagNum = TAG_NUM_shouboqin;
                showFragment(shouboqinFragment);
                break;
            case R.id.btn_lyre7:
                mTextView.setText(getString(R.string.lyre7));
                currentFragmentTagNum = TAG_NUM_lyre7;
                showFragment(lyre7Fragment);
                break;
            case R.id.btn_lyre15:
                mTextView.setText(getString(R.string.lyre15));
                currentFragmentTagNum = TAG_NUM_lyre15;
                showFragment(lyre15Fragment);
                break;
            case R.id.btn_guzheng:
                mTextView.setText(getString(R.string.guzheng));
                currentFragmentTagNum = TAG_NUM_guzheng;
                showFragment(guzhengFragment);
                break;
            case R.id.btn_guqin:
                mTextView.setText(getString(R.string.guqin));
                currentFragmentTagNum = TAG_NUM_guqin;
                showFragment(guqinFragment);
                break;
            case R.id.btn_pipa:
                mTextView.setText(getString(R.string.pipa));
                currentFragmentTagNum = TAG_NUM_pipa;
                showFragment(pipaFragment);
                break;
            case R.id.btn_youkelili:
                mTextView.setText(getString(R.string.youkelili));
                currentFragmentTagNum = TAG_NUM_youkelili;
                showFragment(youkeliliFragment);
                break;
            default:
                mSelectDialog.dismiss();
                break;
        }
    }

    @Override
    public void onXianClick(int position) {

        lastShowXian[currentFragmentTagNum] = position;
        mXianNum.setText(String.valueOf(position + 1));

        if (!hasRecordingPermission()) {
            return;
        }
        int i = position / 5;
        loadBiaoZhunYin(i, position);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.activity_btn_back:
                finish();
                break;
            case R.id.activity_btn_help:
                mShuomingDialog.show(fm, TAG_shuomingDialog);
                break;
            default:
                mSelectDialog.show(fm, TAG_selectDialog);
                break;
        }
    }

    private void showFragment(Fragment f) {
        if (mSoundPool != null) {
            mSoundPool.release();
            mSoundPool = null;
        }
        isExact = true;
        makeAnimation(0);

        mSoundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);

        int i = lastShowXian[currentFragmentTagNum] / 5;
        mXianNum.setText(String.valueOf(lastShowXian[currentFragmentTagNum] + 1));
        setNoteText(i);

        if (!f.isVisible()) {
            fm.beginTransaction()
                    .hide(fm.findFragmentByTag(lastShowFragmentTag))
                    .show(f)
                    .commit();
            lastShowFragmentTag = f.getTag();
        }
        mSelectDialog.dismiss();
    }

    private void loadBiaoZhunYin(final int i, final int position) {
        setNoteText(i);
        if (mSoundId != -1) {
            mSoundPool.stop(mSoundId);
            mSoundPool.unload(mSoundId);
            Log.i("mSoundId",""+mSoundId);
        }
        mSoundId = mSoundPool.load(this, midPath[currentFragmentTagNum][i], 1);
        mSoundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
            @Override
            public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
                mSoundPool.play(mSoundId, 1, 1, 0, 0,
                        (float) (Math.pow(RATE,
                                (num_first[currentFragmentTagNum][i] +
                                        num_xians[currentFragmentTagNum][position])) * (jzFre / 440.0)));
            }
        });
    }

    private void setNoteText(int i) {
        int num = num_first_letter[currentFragmentTagNum][i] +
                num_xians[currentFragmentTagNum][lastShowXian[currentFragmentTagNum]];
        mLetText.setText(STR_LET[num % 12]);
        mNumText.setText(String.valueOf(num / 12 + first_num[currentFragmentTagNum][i]));
        double j = 12 * (num / 12 + first_num[currentFragmentTagNum][i] - 4) + (num % 12 - 9);
        if (currentFragmentTagNum == TAG_NUM_lyre7 || currentFragmentTagNum == TAG_NUM_lyre15) {
            jzFre = 442.0;
        } else {
            jzFre = 440.0;
        }
        fre = (float) (Math.pow(RATE, j) * jzFre);
        //j为当前音阶与基准音相差的半音数(j = 12 * 下标相差 + 字符相差)
    }

    private void makeAnimation(float pos) {
        animation = new RotateAnimation(prePos, pos, Animation.RELATIVE_TO_SELF, 0.5f, Animation.ABSOLUTE, xuanzhuandianY);
        animation.setDuration(200);
        animation.setFillAfter(true);
        animation.setInterpolator(new AccelerateDecelerateInterpolator());
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                pointer.startAnimation(animation);
                if (!isExact) {
                    pointer.setBackgroundResource(R.drawable.pic_pointer2);
                } else {
                    pointer.setBackgroundResource(R.drawable.pic_pointer);
                }
            }
        });
        prePos = pos;
    }

    private void startShiyin() {
        audioProcess = new AudioProcess();
        audioProcess.setOnFreqChangedListener(new AudioProcess.OnFreqChangedListener() {
            @Override
            public void onFreqChanged(float freq) {
                if (freq > 20 && freq < 2 * fre) {
                    isExact = freq > fre / RATE_20 && freq < fre * RATE_20;    //音是否准确(相差20音分即视为准确)
                    makeAnimation(getDegree(freq));

                    k[i % 2] = freq;

                    if (k[0] < k[1] * RATE_10 && k[0] > k[1] / RATE_10) {
                        if (Math.abs(k[0] - fre) < Math.abs(k[1] - fre)) {
                            j = k[0];
                        } else {
                            j = k[1];
                        }
                    }
                    i++;
                    if (i > 100000) {
                        i = 0;
                    }
                } else if (j != -1) {
                    isExact = j > fre / RATE_20 && j < fre * RATE_20;
                    makeAnimation(getDegree(j));
                    j = -1;
                    i = 0;
                }
            }
        });
        audioProcess.start();
    }

    private void stopShiyin() {
        if (audioProcess != null) {
            audioProcess.stop();
            audioProcess = null;
        }
        if (animation != null) {
            animation.cancel();
        }
    }

    /**
     * 指针显示范围20Hz—2*fre,
     * 中间 -36.5 — 36.5度范围为fre±40音分,
     * 其余为两侧各20度,
     * fre±10音分判定为准确，指针在正中间
     */
    private float getDegree(float freq) {
        if (freq <= fre / RATE_40) {
            Log.d("MainActivity", "频率为" + freq + "，太小，中心频率为" + fre);
            return (float) (-56.5 + 20 * (freq - 20) / (fre / RATE_40));
        } else if (freq > fre * RATE_40) {
            Log.d("MainActivity", "频率为" + freq + "，太大" + "，中心频率为" + fre);
            return (float) (36.5 + 20 * (freq - fre * RATE_40) / (fre * (2 - RATE_40)));
        } else if (freq < fre * RATE_10 && freq > fre / RATE_10) {
            Log.d("MainActivity", "频率为" + freq + "，中心频率为" + fre);
            return 0;
        } else {
            Log.d("MainActivity", "频率为" + freq + "，中心频率为" + fre);
            return (float) (36.5 * (freq - fre) / (fre * RATE_40 - fre / RATE_40));
        }
//        if (freq < fre / RATE_2) {
//            Log.d("MainActivity", "频率为" + freq + "，太小，中心频率为" + fre);
//            return -56.5f;
//        } else if (freq >= fre / RATE_2 && freq < fre / RATE_10) {
//            Log.d("MainActivity", "频率为" + freq + "，太大" + "，中心频率为" + fre);
//            return (float) (56.5 * (freq - fre / RATE_10) / (fre / RATE_10 - fre / RATE_2));
//        } else if (freq <= fre * RATE_10 && freq >= fre / RATE_10) {
//            Log.d("MainActivity", "频率为" + freq + "，中心频率为" + fre);
//            return 0;
//        } else if (freq > RATE_10 * fre && freq <= fre * RATE_2) {
//            Log.d("MainActivity", "频率为" + freq + "，中心频率为" + fre);
//            return (float) (56.5 * (freq - fre * RATE_10) / (fre * RATE_2 - fre * RATE_10));
//        } else {
//            Log.d("MainActivity", "频率为" + freq + "，中心频率为" + fre);
//            return 56.5f;
//        }
    }

    private boolean hasRecordingPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, 0);
                return false;
            }
        }
        return true;
    }
}
